# -*- coding: utf-8 -*-
# this file is released under public domain and you can use without limitations

#########################################################################
## This is a sample controller
## - index is the default action of any application
## - user is required for authentication and authorization
## - download is for downloading files uploaded in the db (does streaming)
## - call exposes all registered services (none by default)
#########################################################################
import base64

if False:
    from gluon.tools import *


def index():
    welcome_package = {}
    master_content = {'categories': [], 'categories_info': {}}
    if session.get('RUN_ONCE', 0) == 1:
        # First time login, set up a "welcome package" and
        # then delete these session objects
        welcome_package = {'new_user': session.NEW_USER,
                           'new_user_passwd': session.NEW_USER_PASSWD}
        del session.NEW_USER
        del session.NEW_USER_PASSWD
        del session.RUN_ONCE
    else:
        # Regular forum visit, construct the contents of the main
        # Page:

        # Get the membership of the logged in user, note that under
        # normal circumstances, this should always return ONE membership,
        # based on PyForum's own logic
        is_auth = auth.is_logged_in()
        user_role = ''
        if is_auth:
            # auth.user_groups --> {id1: 'group1', id2: 'group2', ..}
            user_role = auth.user_groups.values()[0]
            #membership = db(
            #    (db.auth_membership.user_id == auth.user_id) &
            #    (db.auth_group.id == db.auth_membership.group_id)).select(
            #    db.auth_group.role).first()
            #user_role = membership.role

        # Get the categories that the user is allowed to view

        user_role_cond = False
        if user_role:
            user_role_cond = (
                db.zf_forum_category.cat_visible_to.contains(user_role)) | (
                db.zf_forum_category.cat_visible_to == ''
            )
        else:
            user_role_cond = db.zf_forum_category.cat_visible_to == ''

        categories = db(
            (user_role_cond) & (
            db.zf_forum.cat_id == db.zf_forum_category.id)).select(
            db.zf_forum_category.id,
            db.zf_forum_category.cat_name,
            db.zf_forum_category.cat_desc,
            db.zf_forum.id,
            db.zf_forum.forum_title,
            db.zf_forum.forum_desc,
            db.zf_forum.modifying_date,
            orderby=(db.zf_forum_category.cat_sort | db.zf_forum.forum_sort)
        )

        if categories:
            for cat in categories:
                cat_id = cat.zf_forum_category.id
                cat_exists = cat_id in master_content['categories']

                # Here are the attributes that the main page will have
                category_info = {
                    'id': cat.zf_forum_category.id,
                    'cat_name': cat.zf_forum_category.cat_name,
                    'cat_desc': cat.zf_forum_category.cat_desc
                }
                # Get Posts
                posts = db(
                    (db.zf_topic.forum_id == cat.zf_forum.id) &
                    (db.zf_topic.parent_id == 0)).count()
                replies = db(
                    (db.zf_topic.forum_id == cat.zf_forum.id) &
                    (db.zf_topic.parent_id > 0)).count()
                sum = db.zf_topic.hits.sum()
                views = db(
                    db.zf_topic.forum_id == cat.zf_forum.id).select(
                    sum).first()[sum]
                forum_info = {
                    'id': cat.zf_forum.id,
                    'forum_title': cat.zf_forum.forum_title,
                    'forum_desc': cat.zf_forum.forum_desc,
                    'modifying_date': cat.zf_forum.modifying_date,
                    'posts': posts,
                    'replies': replies,
                    'views': views if views is not None else 0
                }

                if cat_exists:
                    master_content['categories_info'][cat_id]['forums_list'].append(
                        forum_info)
                else:
                    master_content['categories'].append(cat_id)
                    master_content['categories_info'].update(
                        {
                            cat_id: {
                                'category_info': category_info,
                                'forums_list': [forum_info]
                            }
                        }
                    )

        # Master Content Signature:
        ##master_content['catgories'] = [cat1, cat3, cat8, ..]
        ##master_content['categories_info'] = {
        ##    1: {
        ##        'category_data': cat_dict,
        ##        'forums_list': forums_list
        ##    }
        ##    {..}
        ##

        # Get the latest topic that has the "system_annoncement_flag set
        system_announcement = db(
            (db.zf_topic.system_announcement_flag == True) &
            (db.zf_topic.parent_flag == True)).select(
            db.zf_topic.id,
            db.zf_topic.title,
            db.zf_topic.contents,
            orderby=~db.zf_topic.modifying_date).first()
        master_content.update({'system_announcement': system_announcement})

    return dict(
        welcome_package=welcome_package,
        master_content=master_content)


def forum():
    req = request.vars
    view_info = {}
    view_info['errors'] = []
    view_info['all_topics'] = 0
    security_info = {'can_add': False, 'can_reply': False}
    user_id = auth.user_id

    if req.remove_topics:
        forum_id = (req.forum_id)
        forum = db(db.zf_forum.id == forum_id).select().first()
    else:
        forum_id = int(request.args[0])
        # Here handle subscription/unsubscriptions
        if len(request.args) > 1 and auth.is_logged_in():
            subscription_flag = int(request.args[1])
            is_subscription = db(
                (db.zf_member_subscriptions.subscription_id == forum_id) &
                (db.zf_member_subscriptions.user_id == user_id)).select(
                db.zf_member_subscriptions.id)
            if subscription_flag == 1:  # Request Subscription
                if len(is_subscription) == 0:
                    # (new) Subscription
                    db.zf_member_subscriptions.insert(
                        user_id=user_id,
                        subscription_id=forum_id,
                        subscription_type='F', subscription_active=True)
                else:
                    # Update an existing subscription back to "true"
                    db(
                        (db.zf_member_subscriptions.subscription_id ==
                         forum_id) &
                        (db.zf_member_subscriptions.subscription_type == 'F') &
                        (db.zf_member_subscriptions.user_id ==
                         user_id)).update(subscription_active=True)
            else:  # User is requesting removal (or inactivate subscription)
                if len(is_subscription) > 0:
                    db(
                        (db.zf_member_subscriptions.subscription_id ==
                         forum_id) &
                        (db.zf_member_subscriptions.user_id ==
                         user_id)).update(subscription_active=False)
        forum = db(db.zf_forum.id == forum_id).select().first()

    if not forum:
        redirect(URL(r=request, c='default', f='invalid_request'))

    # Information to pass regarding system variables, etc
    # Forum Subscription:
    view_info.update(
        {'subscribed_to_forum': forumhelper.has_forum_subscription(
            forum_id, user_id)})
    # Max preview length:
    view_info.update({'zfsp_topic_teaser_length': int(
        forumhelper.get_system_property('zfsp_topic_teaser_length', 250))})

    # If forum allows anonymous postings, bypass, otherwise, check if
    # the user is logged in
    user_can_enter = True
    if not auth.is_logged_in() and not forum.anonymous_viewaccess:
        user_can_enter = False

    # If user can enter the forum, check for memberships of both the
    # forum itself and the user's
    if user_can_enter:
        # Admins basically can add/reply regardless of any settings
        if auth.has_membership(forum_memberships['FORUM_ADMINISTRATOR']):
            security_info['can_add'] = True
            security_info['can_reply'] = True
        else:
            # See if the user can create topics or respond to them:

            # Can the user add topics?
            if len(forum.add_postings_access_roles):
                # Loop through the roles for this forum and see if the
                # user has any role membership, if he/she does, then
                # it is allowed to add topics.
                auth_add_roles = forum.add_postings_access_roles.split(',')
                security_info['can_add'] = len([
                    role for role in auth_add_roles
                    if auth.has_membership(role)
                ]) > 0
            else:
                # If the table contains an empty value, it means that the
                # forum is "open", anyone can add topics (this should be
                # relatively uncommon)
                security_info['can_add'] = True

            # Can the user reply to topics?
            if len(forum.reply_postings_access_roles):
                auth_reply_roles = forum.reply_postings_access_roles.split(
                    ',')
                security_info['can_reply'] = len([
                    role for role in auth_reply_roles
                    if auth.has_membership(role)
                ]) > 0
            else:
                # If the table contains an empty value, it means that the
                # forum is "open", anyone can respond to topics (this should
                # be relatively uncommon)
                security_info['can_reply'] = True

        # Deletion of topics has been requested.
        # TODO Check if Admin is needed before this...
        if req.del_topics:
            for req_var in req:
                if req_var[:10] == 'del_topic_':
                    del_topic_id = int(req[req_var])
                    db(db.zf_topic.parent_id ==
                       del_topic_id).delete()  # Children
                    db(db.zf_topic.id == del_topic_id).delete()  # Parent
                    view_info.update({'topics_removed': True})

        # Pagination Manager Part I/II
        start = int(req.get('start', 0))
        topics_per_page = int(
            forumhelper.get_system_property('zfsp_threads_per_page', 15))

        # all Topics
        all_topics = db((db.zf_topic.forum_id == forum_id) & (
            db.zf_topic.parent_flag == True)).count()
        view_info['all_topics'] = all_topics
        parent_topics = db(
            (db.zf_topic.forum_id == forum_id) &
            (db.zf_topic.parent_flag == True)).select(
            orderby=(~db.zf_topic.sticky_flag, ~db.zf_topic.modifying_date),
            limitby=(start, start + topics_per_page))

        # Pagination Manager Part II/II
        pagination_widget = forumhelper.pagination_widget(
            all_topics,
            start,
            URL(r=request, c='default', f='view_forum', args=[forum.id]),
            'forum')
        view_info.update({'pagination_widget': pagination_widget})

        # Now plug in the information regarding their children
        topic_replies_info = {}
        for topic in parent_topics:
            # Get the number of children topics for this (parent) topic
            topic_replies_info.update({topic.id: db(
                db.zf_topic.parent_id == topic.id).count()})
            # Topic Subscription
            if forumhelper.has_topic_subscription(topic.id, user_id):
                view_info.update({topic.id: {'subscribed_to_topic': True}})
            else:
                view_info.update({topic.id: {'subscribed_to_topic': False}})

        return dict(request=request, forum=forum, parent_topics=parent_topics,
                    view_info=view_info, security_info=security_info,
                    topic_replies_info=topic_replies_info)
    else:
        redirect(URL(r=request, c='default', f='unauthorized'))


def add_topic():
    req = request.vars
    view_info = {}
    view_info['errors'] = []
    view_info['messages'] = []
    captcha = forumhelper.gen_tmp_passwd()
    view_info['anon_captcha'] = captcha
    view_info['anon_captcha_base64'] = base64.standard_b64encode(captcha)
    security_info = {'can_add': False, 'can_reply': False}
    is_admin = auth.has_membership(forum_memberships['FORUM_ADMINISTRATOR'])
    _emoticons = [  # Possible Deprecation
        'icon_arrow.png',
        'icon_biggrin.png',
        'icon_confused.png',
        'icon_cool.png',
        'icon_cry.png',
        'icon_exclaim.png',
        'icon_idea.png',
        'icon_lol.png',
        'icon_mad.png',
        'icon_mrgreen.png',
        'icon_neutral.png',
        'icon_question.png',
        'icon_razz.png',
        'icon_redface.png',
        'icon_rolleyes.png',
        'icon_sad.png',
        'icon_smile.png',
        'icon_twisted.png',
        'icon_wink.png']
    # TODO Fix emoticon issue
    emoticons = []
    view_info.update({'emoticons': emoticons})
    if req.form_submitted:
        forum_id = int(req.forum_id)
        forum = db(db.zf_forum.id == forum_id).select(
            db.zf_forum.forum_title).first()
        view_info.update({'forum': forum})
        if req.add_topic:
            # First thing, required fields check:
            if (req.title and req.content) and (auth.is_logged_in() or (
                not auth.is_logged_in() and base64.standard_b64encode(
                    req.captcha_response) == req.c)):
                content = req.content
                # Parse the title
                # Ignore ALL html tags AND do not convert it
                title = XML(req.title, sanitize=True)

                creation_user = auth.user_id or 0
                modifying_user = creation_user
                if is_admin:
                    locked_flag = req.locked_flag is not None
                    sticky_flag = req.sticky_flag is not None
                    system_announcement_flag = req.system_announcement_flag \
                        is not None
                    creation_date = req.creation_date
                    modifying_date = req.modifying_date
                else:
                    locked_flag = False
                    sticky_flag = False
                    system_announcement_flag = False
                    creation_date = request.now
                    modifying_date = creation_date

                # Add Signature from Member Profile if requested.
                if req.add_signature:
                    signature = forumhelper.get_member_property(
                        'zfmp_signature', creation_user, '')
                    if signature:
                        content += '\n\n<code>\n%s</code>' % (signature)

                # Add the topic
                topic_id = db.zf_topic.insert(
                    forum_id=forum_id,
                    title=XML(title, sanitize=True),
                    contents=XML(content, sanitize=True),
                    creation_user_id=creation_user,
                    creation_date=creation_date,
                    modifying_user_id=modifying_user,
                    modifying_date=modifying_date,
                    parent_flag=True,
                    locked_flag=locked_flag,
                    disabled_flag=False,
                    sticky_flag=sticky_flag,
                    poll_flag=False,
                    system_announcement_flag=system_announcement_flag,
                    ip_address=request.client)

                # Update the forum with the latest modification date
                db(db.zf_forum.id == forum_id)._update(
                    modifying_date=request.now
                )

                # Notify Subscribed users about changes in this Forum
                forumhelper.setup_notifications(subscription_id=forum_id,
                                                subscription_type='F',
                                                now=request.now)

                # Subscribe user to topic if requested
                if req.add_subscription:
                    forumhelper.add_topic_subscription(
                        topic_id, creation_user)  # ID

                # Increment the number of postings for this user
                postings = int(forumhelper.get_member_property(
                    'zfmp_postings', creation_user, '0')) + 1
                forumhelper.put_member_property('zfmp_postings',
                                                creation_user,
                                                str(postings))

                view_info['messages'].append('Topic has been added')
                redirect(URL(r=request,
                             c='default',
                             f='forum',
                             args=[forum_id],
                             vars=dict(added='1')))
            else:
                view_info['errors'].append('Please make sure all required '
                                           'fields are properly filled')
                return dict(request=request,
                            view_info=view_info,
                            forum_id=forum_id)
        elif req.preview_b:
            content = req.content
            if is_admin:
                creation_user = req.creation_user
            else:
                creation_user = auth.user_id
            # Add Signature from Member Profile if requested.
            if req.add_signature:
                signature = forumhelper.get_member_property('zfmp_signature',
                                                            creation_user,
                                                            '')
                if signature:
                    content += '\n\n<code>\n{}</code>'.format(signature)
            view_info.update({'preview': content})
            return dict(request=request,
                        view_info=view_info,
                        forum_id=forum_id)
        else:
            redirect(URL(r=request,
                         c='default',
                         f='forum',
                         args=[forum_id]))
    else:
        forum_id = int(request.args[0])
        forum = db(db.zf_forum.id == forum_id).select(
            db.zf_forum.forum_title).first()
        view_info.update({'forum': forum})
        return dict(request=request,
                    view_info=view_info,
                    forum_id=forum_id)


def topic():
    req = request.vars
    view_info = {}
    view_info['errors'] = []
    security_info = {'can_add': False, 'can_reply': False}
    parent_topic_removed = False
    user_id = auth.user_id or 0
    emoticons = []
    user_is_admin = auth.has_membership(
        forum_memberships['FORUM_ADMINISTRATOR'])
    # TODO: Fix This
    _emoticons = [
        'icon_arrow.png', 'icon_biggrin.png', 'icon_confused.png',
        'icon_cool.png', 'icon_cry.png', 'icon_exclaim.png',
        'icon_idea.png', 'icon_lol.png', 'icon_mad.png',
        'icon_mrgreen.png', 'icon_neutral.png', 'icon_question.png',
        'icon_razz.png', 'icon_redface.png', 'icon_rolleyes.png',
        'icon_sad.png', 'icon_smile.png', 'icon_twisted.png',
        'icon_wink.png']
    view_info.update({'emoticons': emoticons})
    captcha = forumhelper.gen_tmp_passwd()
    view_info['anon_captcha'] = captcha
    view_info['anon_captcha_base64'] = base64.standard_b64encode(captcha)
    view_info['messages'] = []

    if req.form_submitted:
        topic_id = (req.topic_id)
    else:
        topic_id = int(request.args[0])
    # Get This topic
    topic = db(db.zf_topic.id == topic_id).select().first()

    if not topic:
        redirect(URL(r=request, c='default', f='invalid_request'))

    if topic.parent_flag:

        # Handle Topic subscriptions here
        if len(request.args) > 1:
            subscription_request = int(request.args[1]) == 1
            if subscription_request:
                forumhelper.add_topic_subscription(topic_id, user_id)
            else:
                forumhelper.del_topic_subscription(topic_id, user_id)

        # Handle Topic Hits Here as well
        db(db.zf_topic.id == topic_id).update(hits=topic.hits+1)

        # Grab the forum
        forum = db(db.zf_forum.id == topic.forum_id).select().first()

        # Admins can do anything..
        if user_is_admin:
            security_info['can_add'] = True
            security_info['can_reply'] = True
        else:
            # If this field has something, evaluate
            if len(forum.add_postings_access_roles):
                # Loop through the roles for this forum and see if the
                # user has any role membership, if he/she does, then
                # it is allowed to add topics.
                auth_add_roles = forum.add_postings_access_roles.split(',')
                security_info['can_add'] = len([
                    role for role in auth_add_roles
                    if auth.has_membership(role)
                ]) > 0
            else:
                # Otherwise it is empty, topics can be added by
                # Anonymous
                security_info['can_add'] = True

            # Same for replies
            if len(forum.reply_postings_access_roles):
                auth_reply_roles = forum.reply_postings_access_roles.split(
                    ',')
                security_info['can_reply'] = len([
                    role for role in auth_reply_roles
                    if auth.has_membership(role)
                ]) > 0
            else:
                security_info['can_reply'] = True

        # HANDLE Removals/Submission of new topic, etc
        # Was a removal requested?
        if req.remove and user_is_admin:
            # At this point, there are several important things to consider,
            # if the admin requested removal of the parent topic, along with
            # one or more children topics, there is no point in processing
            # the children since they'll be deleted anyway
            if req.get('remove_topic_parent_%s' % (topic_id), '') != '':
                # Removal of parent requested, remove children first,
                # then parent.
                db(db.zf_topic.parent_id == topic_id).delete()
                db(db.zf_topic.id == topic_id).delete()
                parent_topic_removed = True
            else:
                # Removal of certain children topics requested only
                for req_var in req:
                    if req_var[:19] == 'remove_topic_child_':
                        child_topic_id = int(req[req_var])
                        db(db.zf_topic.id == child_topic_id).delete()
        if parent_topic_removed:
            redirect(URL(r=request, c='default', f='forum',
                         args=[forum.id]))
        else:

            # Here now check if the user is trying to add a new response
            # (or preview)
            if req.preview:
                view_info.update({'preview': True})
            elif (req.form_submitted
                  and security_info['can_reply']
                  and not auth.is_logged_in()
                  and base64.standard_b64encode(
                    req.captcha_response) != req.c):
                # Use this slot when captcha fails
                # This test must be evaluated when:
                # - The User is Anonymous
                # - AND the forum allow anonymous replies
                view_info['errors'].append('Please make sure all required '
                                           'fields are properly filled')
                view_info.update({'preview': True})
            elif (req.add and (
                security_info['can_reply'] or
                auth.has_membership(
                    forum_memberships['FORUM_ADMINISTRATOR']))):
                if req.response_content.strip():
                    now = request.now.strftime('%Y-%m-%d %H:%M:%S')
                    #raise ValueError(markmin2html(req.response_content))
                    # User is requesting addition of a response (child topic)
                    db.zf_topic.insert(
                        forum_id=forum.id,
                        title=topic.title,
                        contents=req.response_content,
                        parent_id=topic_id,
                        creation_user_id=user_id,
                        creation_date=now,
                        modifying_user_id=user_id,
                        modifying_date=now,
                        hits=0,
                        parent_flag=False,
                        locked_flag=False,
                        disabled_flag=False,
                        sticky_flag=False,
                        poll_flag=False,
                        system_announcement_flag=False,
                        reply_to_topic_id=0,
                        ip_address=request.remote_addr)

                    # Update the modifying date, and the modifying user of
                    # its parent also
                    db(db.zf_topic.id == topic_id)._update(
                        modifying_date=now,
                        modifying_user_id=user_id
                    )

                    # Also udpate the forum's "last modified date" and user
                    db(db.zf_forum.id == forum.id).update(
                        modifying_date=request.now
                    )

                    # Increment the number of postings for this user
                    # IF the user is not anonymous
                    if user_id:
                        postings = int(forumhelper.get_member_property(
                            'zfmp_postings', user_id, '0')) + 1
                        forumhelper.put_member_property('zfmp_postings',
                                                        user_id, str(postings))

                    # Notify Subscribed users about changes in this topic
                    forumhelper.setup_notifications(subscription_id=topic_id,
                                                    subscription_type='T',
                                                    now=request.now)

                    view_info['messages'].append('Response has been added')
                    redirect(URL(r=request,
                                 c='default',
                                 f='topic',
                                 args=[topic_id],
                                 vars=dict(added='1')))

                else:
                    view_info['errors'].append(
                        'Content must be specified for the reply')

            # Information to pass regarding system variables, etc
            # Topic Subscription:
            view_info.update({
                'subscribed_to_topic': forumhelper.has_topic_subscription(
                    topic_id, user_id)})

            # Pagination Manager Part I/II
            start = int(req.get('start', 0))
            responses_per_page = int(forumhelper.get_system_property(
                'zfsp_responses_per_page', 15))
            # Children Topics
            all_children = db(db.zf_topic.parent_id == topic.id).count()
            children = db(db.zf_topic.parent_id == topic.id).select(
                db.zf_topic.ALL, orderby=db.zf_topic.modifying_date,
                limitby=(start, start+responses_per_page))

            # Pagination Manager Part II/II
            pagination_widget = forumhelper.pagination_widget(
                all_children, start, URL(r=request,
                                         c='default',
                                         f='view_topic',
                                         args=[topic_id]), 'topic')
            view_info.update({'pagination_widget': pagination_widget})

            return dict(request=request,
                        security_info=security_info,
                        forum=forum,
                        topic=topic,
                        children=children,
                        view_info=view_info)
    else:
        redirect(URL(r=request, c='default', f='invalid_request'))

# Contact the administrators..
def contact():
    """ Contact Admin - This can allow anonymous users to post spam, so
    for them, I'll add some "poor man's captcha"

    """
    view_info = {}
    view_info['errors'] = []
    captcha = forumhelper.gen_tmp_passwd()
    view_info['anon_captcha'] = captcha
    view_info['anon_captcha_base64'] = base64.standard_b64encode(captcha)
    user_id = auth.user_id
    req = request.vars
    msg = req.message.strip()
    subject = req.subject.strip()
    if req.form_submitted:
        if req.send_b:
            if subject and msg:
                if auth.is_logged_in() or (
                    not auth.is_logged_in() and base64.standard_b64encode(
                        req.captcha_response) == req.c):
                    db.zf_admin_messages.insert(
                        user_id=user_id,
                        subject=subject,
                        msg=msg,
                        creation_date=request.now,
                        read_flag=False)
                    redirect(URL(r=request, c='default', f='index'))
                else:
                    view_info['errors'].append('Invalid humanity challenge '
                                               'response, please try again')
                    return dict(request=request, view_info=view_info)
            else:
                view_info['errors'].append('Both Subject and Message are '
                                           'required fields')
                return dict(request=request, view_info=view_info)
        else:
            redirect(URL(r=request, c='default', f='index'))
    else:
        return dict(request=request, view_info=view_info)

def login():
    view_info = {}
    view_info['errors'] = []
    req = request.vars
    is_auth = auth.is_logged_in()
    if is_auth:
        redirect(URL(r=request, c='default', f='index', vars=dict(al=1)))
    else:
        if req.form_submitted:
            auth_user = req.auth_email
            auth_passwd = req.auth_passwd
            if auth_user and auth_passwd:
                user = auth.login_bare(auth_user, auth_passwd)
                if user:
                    redirect(URL(r=request, c='default', f='index'))
                else:
                    view_info['errors'].append(
                        'Invalid credentials supplied, please try again.')
            else:
                view_info['errors'].append(
                    'Both username and password are required fields.')
        return dict(view_info=view_info)

def logout():
    auth.logout(onlogout=lambda user: session.update({'auth':None}))

def unauthorized():
    return dict()


def invalid_request():
    return dict()


def user():
    """
    exposes:
    http://..../[app]/default/user/login
    http://..../[app]/default/user/logout
    http://..../[app]/default/user/register
    http://..../[app]/default/user/profile
    http://..../[app]/default/user/retrieve_password
    http://..../[app]/default/user/change_password
    http://..../[app]/default/user/manage_users (requires membership in
    use @auth.requires_login()
        @auth.requires_membership('group name')
        @auth.requires_permission('read','table name',record_id)
    to decorate functions that need access control
    """
    return dict(form=auth())

def preferences():
    view_info = {}
    view_info['errors'] = []
    view_info['props'] = {}
    req = request.vars
    user_id = auth_user.get_user_id()
    # Avatar Restrictions (px)
    AVATAR_MAX_HEIGHT = 100
    AVATAR_MAX_WIDTH  = 120
    AVATAR_MAX_SIZE   = 15000 # Bytes
    user_email = 'needemail@email.com'
    view_info['props'].update({'real_name':
        forumhelper.get_member_property('zfmp_real_name', user_id, '')})
    view_info['props'].update({'web_page':
        forumhelper.get_member_property('zfmp_web_page', user_id, '')})
    view_info['props'].update({'country':
        forumhelper.get_member_property('zfmp_country', user_id, '')})
    view_info['props'].update({'signature':
        forumhelper.get_member_property('zfmp_signature', user_id, '')})
    view_info['props'].update({'locale':
        forumhelper.get_member_property('zfmp_locale', user_id, '')})
    view_info['props'].update({'allow_pm_use':
        forumhelper.get_member_property('zfmp_allow_pm_use', user_id, '')})
    view_info['props'].update({'postings':
        forumhelper.get_member_property('zfmp_postings', user_id, '0')})
    view_info['props'].update({'last_login':
        forumhelper.get_member_property(
            'zfmp_last_login', user_id, str(XML(T('Never'))))})
    view_info['props'].update({'username':
        forumhelper.get_member_property(
            'zfmp_display_name', user_id, 'user_%s' % (user_id))})
    forum_subscriptions = db((db.zf_member_subscriptions.user_id == user_id) &
        (db.zf_member_subscriptions.subscription_type == 'F') &
        (db.zf_member_subscriptions.subscription_id == db.zf_forum.id) &
        (db.zf_member_subscriptions.subscription_active == True)).select(
        db.zf_forum.id, db.zf_forum.forum_title)
    topic_subscriptions = db((db.zf_member_subscriptions.user_id == user_id) &
        (db.zf_member_subscriptions.subscription_type == 'T') &
        (db.zf_member_subscriptions.subscription_id == db.zf_topic.id) &
        (db.zf_member_subscriptions.subscription_active == True)).select(
        db.zf_topic.id, db.zf_topic.title)
    available_languages = db(db.zf_available_languages.enabled == True).select(
        db.zf_available_languages.ALL,
        orderby=db.zf_available_languages.language_desc)

    if req.form_submitted:
        if req.update_b:
            # Standard Properties
            forumhelper.put_member_property('zfmp_real_name', user_id,
                                            req.real_name)
            forumhelper.put_member_property('zfmp_web_page', user_id,
                                            req.web_page)
            forumhelper.put_member_property('zfmp_country', user_id,
                                            req.country)
            forumhelper.put_member_property('zfmp_signature', user_id,
                                            req.signature)
            forumhelper.put_member_property('zfmp_locale', user_id,
                                            req.locale)
            if req.allow_pm_use:
                zfmp_allow_pm_use = "1"
            else:
                zfmp_allow_pm_use = ""
            forumhelper.put_member_property('zfmp_allow_pm_use', user_id,
                                            zfmp_allow_pm_use)

            # "Username" is a new member property called 'zfmp_display_name'
            # Which is only an identifier for the user, which they can change,
            # however, there cannot be two users with the same name, so
            # if the username is taken, notify the user to change it, or
            # use the default of "user_[id]"
            username = req.username.strip()
            if username:
                # Check if this username is already taken... and that
                # user is (obviously) not yourself
                if db(
                    (db.zf_member_properties.property_value.lower() == \
                     username.lower()) &
                    (db.zf_member_properties.property_id == \
                     db.zf_member_properties_skel.id) &
                    (db.zf_member_properties_skel.property_name == \
                     'zfmp_display_name') &
                    (db.zf_member_properties.user_id != user_id)).count():
                        view_info['errors'].append('This username already '
                                                   'exists, please choose '
                                                   'another one')
                else:
                    # Nope, does not exist, update..
                    forumhelper.put_member_property('zfmp_display_name',
                                                    user_id, username)
            else:
                view_info['errors'].append('The Username value cannot be '
                                           'empty')

            # Topic Subscriptions
            remove_topic_subscription = req.remove_topic_subscription
            if remove_topic_subscription:
                if type(remove_topic_subscription) == type([]):
                    for topic_id in remove_topic_subscription:
                        forumhelper.del_topic_subscription(int(topic_id),
                                                           user_id)
                else:
                    forumhelper.del_topic_subscription(
                        int(remove_topic_subscription), user_id)

            # Forum Subscriptions
            remove_forum_subscription = req.remove_forum_subscription
            if remove_forum_subscription:
                if type(remove_forum_subscription) == type([]):
                    for forum_id in remove_forum_subscription:
                        forumhelper.del_forum_subscription(int(forum_id),
                                                           user_id)
                else:
                    forumhelper.del_forum_subscription(
                        int(remove_forum_subscription), user_id)

            # Password Changes
            if req.new_passwd or req.new_passwd_confirm:
                if req.new_passwd == req.new_passwd_confirm:
                    hash_passwd = hashlib.sha1(
                        auth_user.get_user_name() + req.new_passwd).hexdigest()
                    db(db.auth_users.id == user_id).update(
                        auth_passwd=hash_passwd)
                else:
                    view_info['errors'].append('Password and confirmation do '
                                               'not match, please try again')

            # Avatars
            if req.remove_avatar:
                db(db.zf_member_avatars.user_id == user_id).update(
                    avatar_active=False)

            # Selected Language (allow storing the "default"
            # value (an empty string))
            forumhelper.put_member_property('zfmp_locale', user_id,
                                            req.lang_code)

            # Crude verification of a FileUpload object set
            try:
                filename = req.avatar_data.filename
            except AttributeError:
                filename = ''

            if filename:
                # Resource: http://epydoc.sourceforge.net/stdlib/cgi.
                # FieldStorage-class.html
                image_data = req.avatar_data.file.read()
                content_type = req.avatar_data.type # "image/png"
                doc_type, ext = content_type.split('/')
                if doc_type == 'image':
                    c_type, width, height = forumhelper.get_image_info(
                        image_data)
                    update_avatar = True
                    if height > AVATAR_MAX_HEIGHT or width > AVATAR_MAX_WIDTH:
                        view_info['errors'].append('Image dimensions exceed '
                                                   'the limits set by the '
                                                   'administrator: (H:'
                                                   '%spx, W:%spx)' % (height,
                                                                      width))
                        update_avatar = False
                    if len(image_data) > AVATAR_MAX_SIZE:
                        view_info['errors'].append('Avatar exceeds the '
                                                   'maximum image size set by '
                                                   'the administrator: '
                                                   '%s bytes' % (
                                                    len(image_data)))
                        update_avatar = False

                    if update_avatar:
                        if forumhelper.has_member_avatar(user_id,
                                                         bypass=False):
                            # Update:
                            db(db.zf_member_avatars.user_id==user_id).update(
                                content_type=content_type,
                                avatar_image=image_data, avatar_active=True)
                        else:
                            # Add:
                            db.zf_member_avatars.insert(
                                content_type=content_type,
                                user_id=user_id,
                                avatar_image=image_data, avatar_active=True)

            if view_info['errors']:
                return dict(request=request, view_info=view_info,
                            user_id=user_id, user_email=user_email,
                            forum_subscriptions=forum_subscriptions,
                            topic_subscriptions=topic_subscriptions,
                            available_languages=available_languages)
            else:
                redirect(URL(r=request, c='default', f='preferences',
                             vars=dict(lang=req.lang_code, upd=1)))
        else:
            redirect(URL(r=request, c='default', f='index'))
    else:
        return dict(request=request, view_info=view_info, user_id=user_id,
                    user_email=user_email,
                    forum_subscriptions=forum_subscriptions,
                    topic_subscriptions=topic_subscriptions,
                    available_languages=available_languages)


def get_avatar_image():
    auth_user = request.args[0]
    avatar_info = db(db.zf_member_avatars.auth_user==auth_user).select(
        db.zf_member_avatars.content_type, db.zf_member_avatars.avatar_image)
    response.headers['Content-Type'] = '%s' % (avatar_info[0].content_type)
    return avatar_info[0].avatar_image


@cache.action()
def download():
    """
    allows downloading of uploaded files
    http://..../[app]/default/download/[filename]
    """
    return response.download(request, db)


def call():
    """
    exposes services. for example:
    http://..../[app]/default/call/jsonrpc
    decorate with @services.jsonrpc the functions to expose
    supports xml, json, xmlrpc, jsonrpc, amfrpc, rss, csv
    """
    return service()
